import CanvasUtils from '@/utils/CanvasUtils';
import PlayController from '@/utils/PlayController';
import CanvasEvent, { CanvasEventType } from '@/utils/CanvasUtils/CanvasEvent';
import { Color, RoundRectI, SpotI, SquareI } from '@/utils/CanvasUtils/CanvasType';
import BaseView from '@/paint/view/BaseView';
import BaseElement from '@/paint/elements/BaseElement';
import TextElement, { TextI } from '@/paint/elements/TextElement';
import RectElement from '@/paint/elements/RectElement';
import RoundElement, { RoundI } from '@/paint/elements/RoundElement';
import RoundRectElement from '@/paint/elements/RoundRectElement';
import VectorLineElement, { VectorI } from '@/paint/elements/VectorLineElement';

export type SpotIEnevt = (spot: SpotI) => void;

export type PaintEventType = keyof PaintEventMap;

export type ElementInputType = keyof ElementInputMap;

export type ElementBaseEventType = keyof ElementBaseEventMap;

export interface StyleI {
	/** 背景颜色 */
	BackgroundColor?: Color;
	/** 边框颜色 */
	BorderColor?: Color;
	/** 线条宽度 */
	LineWidth?: number;
}

/** 画板事件列表 */
export interface PaintEventMap {
	click: SpotIEnevt;
	move: SpotIEnevt;
	resize: () => void;
}

export interface ElementBaseEventMap {
	click: SpotIEnevt;
	move: SpotIEnevt;
	hover: (onHover: boolean, spot: SpotI) => void;
}

/** 元素接口列表 */
export interface ElementInputMap {
	text: TextI;
	rect: SquareI;
	round: RoundI;
	roundRect: RoundRectI;
	vector: VectorI;
}

/** 元素接口列表 */
export interface ElementResultMap {
	text: TextElement;
	rect: RectElement;
	round: RoundElement;
	roundRect: RoundRectElement;
	vector: VectorLineElement;
}

export interface PaintEvent<T extends PaintEventType> {
	target: BaseElement | BaseView | null;
	event: PaintEventMap[T];
}

type PaintTypeListEvent = { [P in PaintEventType]: PaintEvent<P>[] };

export default class Paint {

	/** 播放控制类 */
	private playerController: PlayController;

	/** 画板元素 */
	private canvas: CanvasUtils;

	/** 画板事件 */
	private canvasEvent: CanvasEvent;

	/** 事件列表 */
	private eventTypeList: PaintTypeListEvent = { click: [], move: [], resize: [] };

	/** 绘画元素列表 */
	private elementList: BaseElement[] = [];

	private elementResize!: ResizeObserver;

	/** 画板类 */
	public get Canvas(): CanvasUtils {
		return this.canvas;
	}

	/** 运行状态 */
	public get State(): boolean {
		return this.playerController.State;
	}

	/** 事件列表 */
	public get EventTypeList(): PaintTypeListEvent {
		return this.eventTypeList;
	}

	/**
	 * 构造函数
	 * @param el 画板元素
	 */
	public constructor(el: HTMLCanvasElement) {
		this.playerController = new PlayController(this);
		this.canvasEvent = new CanvasEvent(el);
		this.canvas = new CanvasUtils(el);
		this.ResetCanvasEvent();
	}

	/** 界面自适应 */
	public AutoResize(): void {
		this.Canvas.AutoResize();
	}

	/** 清空画板事件 */
	public ClearCanvasEvent(): void {
		if (this.elementResize) {
			this.elementResize.unobserve(this.Canvas.Element);
		}
		this.canvasEvent.Remove();
	}

	/**
	 * 事件过滤
	 * @param callbackfn 过滤回调函数
	 */
	public EventFilter(callbackfn: (value: PaintEvent<PaintEventType>) => boolean) {
		this.eventTypeList.click = this.eventTypeList.click.filter(callbackfn);
		this.eventTypeList.move = this.eventTypeList.move.filter(callbackfn);
		this.eventTypeList.resize = this.eventTypeList.resize.filter(callbackfn);
	}

	/**
	 * 添加画板事件
	 * @param type 事件类型
	 * @param event 监听的事件
	 */
	public AppendCanvasEvent(type: CanvasEventType, event: (...a: any) => void): () => void {
		return this.canvasEvent.Add(type, event);
	}

	/** 重置画板事件 */
	public ResetCanvasEvent(): void {
		this.ClearCanvasEvent();
		this.elementResize = new ResizeObserver(() => {
			this.AutoResize()
			this.eventTypeList.resize.forEach(item => {
				item.event();
			});
		});
		this.elementResize.observe(this.Canvas.Element);
		// this.AppendCanvasEvent("resize", () => {
		// 	this.AutoResize()
		// 	this.eventTypeList.resize.forEach(item => {
		// 		item.event();
		// 	});
		// });
		this.AppendCanvasEvent("click", ({ offsetX: X, offsetY: Y }) => {
			this.eventTypeList.click.forEach(item => {
				item.event({ X, Y });
			});
		});
		this.AppendCanvasEvent("mousemove", ({ offsetX: X, offsetY: Y }) => {
			this.eventTypeList.move.forEach(item => {
				item.event({ X, Y });
			});
		});
	}

	/** 清空事件 */
	public ClearEvent(): void {
		this.EventFilter(item => item.target === null);
	}

	/**
	 * 添加事件
	 * @param type 事件类型
	 * @param event 事件参数
	 */
	public AddEvent<T extends PaintEventType>(target: BaseElement | BaseView | null, type: T, event: PaintEventMap[T]): VoidFunction {
		const save = { target, event };
		this.eventTypeList[type].push(save as any);
		return () => {
			this.eventTypeList[type] = (this.eventTypeList[type] as any[]).filter((item: any) => item !== save);
		};
	}

	/**
	 * 移除元素
	 * @param element 要移除的元素
	 */
	public RemoveElement(element: BaseElement): void {
		this.elementList.filter(item => item !== element);
		this.EventFilter(item => item.target !== element);
	}

	/**
	 * 添加元素
	 * @param element 要添加的元素
	 */
	public AddElement(element: BaseElement): void {
		this.elementList.push(element);
	}

	/**
	 * 创建元素
	 * @param element 要创建的元素
	 */
	public CreatElement<T extends ElementInputType>(type: T, param: ElementInputMap[T]): ElementResultMap[T];
	public CreatElement(type: ElementInputType, param: any): any {
		if (type === "text") {
			const element = new TextElement(this, param);
			this.AddElement(element);
			return element;
		}
		else if (type === "rect") {
			const element = new RectElement(this, param);
			this.AddElement(element);
			return element;
		}
		else if (type === "round") {
			const element = new RoundElement(this, param);
			this.AddElement(element);
			return element;
		}
		else if (type === "roundRect") {
			const element = new RoundRectElement(this, param);
			this.AddElement(element);
			return element;
		}
		else if (type === "vector") {
			const element = new VectorLineElement(this, param);
			this.AddElement(element);
			return element;
		}
	}

	/**
	 * 清空全部画布元素
	 */
	public Clear(): void {
		this.ClearEvent();
		this.elementList = [];
	}

	/** 更新 */
	public Update(): void {
		const Canvas = this.Canvas;
		Canvas.Clear();
		this.elementList.sort((x, y) => x.Z_Index - y.Z_Index).forEach(item => {
			item.Draw(Canvas);
		});
	}

	/** 运行 */
	public Run(): void {
		this.playerController.Run();
	}

	/** 停止 */
	public async Stop(): Promise<void> {
		await this.playerController.Stop();
	}

	/**
	 * 插入运行
	 * @param call 要插入的回调函数
	 */
	public async Wait(call: () => Promise<void>): Promise<void> {
		await this.playerController.Wait(call);
	}

}
